package com.monitor.core.aspect;

import com.monitor.core.annotation.ControllerMonitor;
import com.monitor.core.bean.ControllerMonitorMessage;
import com.monitor.core.bean.MessageHanlderType;
import com.monitor.core.config.BaseConfig;
import com.monitor.core.handler.MessageFactory;
import com.monitor.core.handler.MessageHandler;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.UUID;

@Aspect
public class ControllerAspect {

    ControllerMonitorMessage controllerMessage;

    boolean isMonitored = false;

    ControllerMonitor controllerMonitor;

    @Resource
    MessageFactory messageFactory;

    public void doBefore(JoinPoint joinPoint) {
        controllerMessage = new ControllerMonitorMessage();
        controllerMessage.setBeginTime(System.currentTimeMillis());
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        if (method.isAnnotationPresent(ControllerMonitor.class)) {
            this.isMonitored = true;
            controllerMessage.setUuid(UUID.randomUUID().toString().replaceAll("-", ""));
            controllerMonitor = method.getAnnotation(ControllerMonitor.class);
            controllerMessage.setApi(controllerMonitor.name());
            ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = ra.getRequest();
            controllerMessage.setVisitorIP(request.getRemoteHost());
            controllerMessage.setParams(request.getParameterMap());
            controllerMessage.setUri(request.getRequestURI());
        }
    }

    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object retval = pjp.proceed();
        return retval;
    }

    public void doAfter(JoinPoint joinPoint) {

    }

    public void doReturn(JoinPoint joinPoint, String retval) {
        controllerMessage.setSuccess(true);
        controllerMessage.setReturnValue(retval);
        controllerMessage.setEndTime(System.currentTimeMillis());
        sendMessage();
    }

    private void sendMessage() {
        if (isMonitored) {
            MessageHandler messageHandler;
            if (controllerMonitor.handlerType() != MessageHanlderType.NULL) {
                messageHandler = messageFactory.getMessageHandler(controllerMonitor.handlerType());
            } else if (!StringUtils.isEmpty(controllerMonitor.handlerName().trim())) {
                messageHandler = messageFactory.getMessageHandler(controllerMonitor.handlerName());
            } else {
                messageHandler = messageFactory.getDefaultMessageHandler();
            }
            controllerMessage.setProject(BaseConfig.project);
            controllerMessage.setHost(BaseConfig.host);
            messageHandler.send(controllerMessage);
        }
    }

    public void doThrowing(JoinPoint joinPoint, Exception e) {
        controllerMessage.setSuccess(false);
        controllerMessage.setException(e);
        controllerMessage.setEndTime(System.currentTimeMillis());
        sendMessage();
    }

}
